﻿using NLog;
using Dapper;
using System.Data;
using System.Linq;
using System.Configuration;
using System.Data.SqlClient;
using System.Collections.Generic;
using SilenthinkContract.Domain;

namespace SilenthinkService
{
    public abstract class ServiceBase
    {
        #region ConnectionManager

        protected static readonly Logger Log = LogManager.GetCurrentClassLogger();
        private static readonly IDictionary<string, string> SqlConnectionStringDic = new Dictionary<string, string>();

        protected internal IDbConnection GetConnection(string name)
        {
            string connectionstring;
            if (SqlConnectionStringDic.ContainsKey(name))
            {
                connectionstring = SqlConnectionStringDic[name];
            }
            else
            {
                connectionstring = ConfigurationManager.ConnectionStrings[name].ConnectionString;
                SqlConnectionStringDic[name] = connectionstring;
            }
            return new SqlConnection(connectionstring);
        }

        #endregion

        #region

        protected internal static IEnumerable<T> Query<T>(IDbConnection connection, SqlBuilder.Template template)
        {
            try
            {
                if (connection.State != ConnectionState.Open)
                {
                    connection.Open();
                }
                return connection.Query<T>(template);
            }
            catch (SqlException e)
            {
                var message = e.Message;
                Log.Warn(message);

                return null;
            }
            finally
            {
                connection.Close();
            }
        }

        protected internal static IPagedList<T> Query<T>(IDbConnection connection, SqlBuilder.Template template,
                                                         int size, int index)
        {
            int count;
            var source = new List<T>();
            connection.EnsureOpen();
            using (var multi = connection.QueryMultiple(template))
            {
                count = multi.Read<int>().FirstOrDefault();
                if (count > 0)
                {
                    source = multi.Read<T>().ToList();
                }
            }
            var result = new PagedList<T>(source, size, index, count);
            return result;
        }

        protected internal static PageList<T> PageList<T>(IDbConnection connection, SqlBuilder.Template template)
        {
            int count;
            var source = new List<T>();
            connection.EnsureOpen();
            using (var multi = connection.QueryMultiple(template))
            {
                count = multi.Read<int>().FirstOrDefault();
                if (count > 0)
                {
                    source = multi.Read<T>().ToList();
                }
            }
            var result = new PageList<T> { TotalRecords = count, Data = source };
            return result;
        }



        protected internal static long InsertReturnLastLongId<T>(T o, IDbConnection connection,
                                                                 SqlBuilder.Template template,
                                                                 IDbTransaction dbTransaction = null)
            where T : IEntity<long>
        {
            var sql = template.RawSql + "SELECT SCOPE_IDENTITY();";

            connection.EnsureOpen();
            var data = connection.Query<decimal>(sql, template.Parameters, dbTransaction).First();
            return (long)data;
        }

        protected internal static int InsertReturnLastId<T>(T o, IDbConnection connection, SqlBuilder.Template template,
                                                            IDbTransaction dbTransaction = null) where T : IEntity<int>
        {
            var sql = template.RawSql + "SELECT SCOPE_IDENTITY();";

            connection.EnsureOpen();
            var data = connection.Query<decimal>(sql, template.Parameters, dbTransaction).First();
            return (int)data;
        }

        protected internal static int Execute(IDbConnection connection, SqlBuilder.Template template,
                                              IDbTransaction dbTransaction = null)
        {
            connection.EnsureOpen();
            return connection.Execute(template, dbTransaction);
        }

        protected internal static int BatchInsert<T>(IDbConnection connection, string sql, IEnumerable<T> values,
                                                     IDbTransaction dbTransaction = null)
        {
            connection.EnsureOpen();
            return connection.BatchInsert(sql, values, dbTransaction);
        }

        #endregion

    }

    #region

    internal static class ConnectionName
    {
        internal static readonly string Base = "SilenthinkBase";
        internal static readonly string Main = "SilenthinkMain";
        internal static readonly string Extra = "SilenthinkExtra";
        internal static readonly string Store = "SilenthinkStore";
        internal static readonly string Order = "SilenthinkOrder";
        internal static readonly string Passport = "SilenthinkPassport";
        internal static readonly string Payment = "SilenthinkPayment";

        internal static readonly string Auction = "SilenthinkAuction";
        internal static readonly string Log = "SilenthinkLog";

    }

    #endregion

    internal static class Database
    {
        internal static class Passport
        {
            internal static class Table
            {
                internal static readonly string User = "[User]";
                internal static readonly string UserExtra = "[User.Extra]";
                internal static readonly string UserProfile = "[User.Profile]";
                internal static readonly string UserAddress = "[User.Address]";
                internal static readonly string UserInvoice = "[User.Invoice]";

                internal static readonly string OAuthConfig = "[OAuthConfig]";
            }
        }

        internal static class Payment
        {
            internal static class Table
            {
                internal static readonly string UserAccount = "[User.Account]";
                internal static readonly string UserTrade = "[User.Trade]";
                internal static readonly string UserRecharge = "[User.Recharge]";

                internal static readonly string RechargePackage = "[Recharge.Package]";
                internal static readonly string RechargePackageRequirement = "[Recharge.Package.Requirement]";

                internal static readonly string PayTrade = "[Pay.Trade]";

                internal static readonly string UserIntegral = "[User.Currency.Integral]";
                internal static readonly string PaymentBank = "[Payment.Bank]";
                internal static readonly string PaymentEBank = "[Payment.EBank]";
                internal static readonly string PaymentPlatform = "[Payment.Platform]";
            }

        }
        internal static class Auction
        {
            internal static class Table
            {
                internal static readonly string Auction = "[Auction]";
                internal static readonly string Bidding = "[Auction.Bidding]";
                internal static readonly string AuctionOrder = "[Auction.Order]";
            }
        }

        internal static class Base
        {
            internal static class Table
            {
                internal static readonly string Location = "[Location]";
                internal static readonly string HelpQuestion = "[HelpQuestion]";
                internal static readonly string EmailAccount = "[Email.Account]";
                internal static readonly string EmailTemplate = "[Email.Template]";
                internal static readonly string EmailQueue = "[Email.Queue]";

            }

        }
        internal static class Order
        {
            internal static class Table
            {
                internal static readonly string Order = "[Order]";
                internal static readonly string OrderExtra = "[Order.Extra]";
                internal static readonly string OrderItem = "[Order.Item]";
                internal static readonly string OrderNote = "[Order.Note]";
            }

        }
        internal static class Store
        {
            internal static class Table
            {
                internal static readonly string ProductCategory = "[ProductCategory]";

                internal static readonly string Product = "[Product]";
                internal static readonly string ProductExtra = "[ProductExtra]";
                internal static readonly string ProductVariant = "[ProductVariant]";

                internal static readonly string ProductAttribute = "[ProductAttribute]";

                internal static readonly string ProductAttributeName = "[ProductAttributeName]";
                internal static readonly string ProductAttributeValue = "[ProductAttributeValue]";

                internal static readonly string Discount = "[Discount]";
                internal static readonly string DiscountRequirement = "[DiscountRequirement]";
                internal static readonly string DiscountProductCategoryMapping = "[DiscountProductCategoryMapping]";
                internal static readonly string DiscountProductVariantMapping = "[DiscountProductVariantMapping]";
                internal static readonly string DiscountUsageHistory = "[DiscountUsageHistory]";

                internal static readonly string ProductAdvisory = "[ProductAdvisory]";
                internal static readonly string ProductReview = "[ProductReview]";



            }
        }

        internal static class Extra
        {
            internal static class Table
            {
                internal static readonly string RegisterLog = "Register.Log";
                internal static readonly string VerificationSms = "[Verification.Sms]";

                internal static readonly string VerificationEmail = "[Verification.Email]";

            }

        }

        internal static class Log
        {
            internal static class Table
            {
                internal static readonly string AppException = "[App.Exception]";
            }

        }
    }
}